Filter with slicers
Slicers are the filter controls the author placed on the map. The chips on the left are built from what the map reports - the slicers, the values each offers and their current state - and they stay in step with the map's own slicer cards (top right of the map): click a chip and the card follows, use a card and the chips follow. Setting a slicer from script is exactly the reader using it, so every layer and chart bound to it follows.
What to notice
getSlicers()lists them;getSlicerValues()returns the values a list slicer offers.- A list slicer's state is
{ values: [...] };nullclears it. Other kinds takevalue,range,date,dateRange,relativeDate,timeRangeortoggled. - One
slicerChangedhandler covers your changes (reason: "command") and the reader's ("user"). - Hiding a slicer switches it off - its selection stops filtering, as it does in a bookmark. To filter with no card on the map, use declared filters (the next example).
The code
The complete page. Swap in your own publish id, and ask the map's author to add your site to its allowed origins.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Filter with slicers - Icon Map Embed API</title>
<link rel="stylesheet" href="https://www.icon-map.com/embed-examples/examples.css"> <!-- demo styling only -->
</head>
<body>
<div class="ex-main">
<div class="ex-side">
<div id="panels">loading...</div>
<h2>Result</h2>
<pre class="ex-readout" id="result"></pre>
<div class="ex-chips" style="margin-top:10px">
<button id="clear">Clear all</button>
<button id="fit">Frame the result</button>
</div>
</div>
<div id="map"></div>
</div>
<script src="https://www.icon-map.com/js/iconmap-embed/2/iconmap-embed.umd.min.js"></script>
<script>
const el = document.getElementById("map");
const map = IconMapEmbed.embed(el, {
publishId: "pub_...",
// The map is a globe: let this page's own background show in the space around it.
background: "transparent",
chrome: { legend: false, layerControl: false, bookmarksBar: false, tourTransport: false },
// The map's slicer cards stay on (top right): use one and the chips follow, click a chip and
// the card follows. Only the chart is hidden. Hiding a slicer would switch it OFF - to filter
// with no card on the map, use filters instead (see "Filter from your page").
visibility: { visuals: { "chart-continent": false } },
events: ["slicerChanged"],
});
map.ready.catch((error) => console.error(error.code, error.message));
const chosen = {}; // slicerId -> Set of values
// The slicers, their fields and the values each offers all come from the map.
map.getSlicers().then(async (slicers) => {
const host = document.getElementById("panels");
host.textContent = "";
for (const slicer of slicers) {
chosen[slicer.id] = new Set(slicer.state?.values ?? []);
const { values } = await map.getSlicerValues({ slicerId: slicer.id });
const title = Object.assign(document.createElement("h2"), { textContent: slicer.name });
const chips = Object.assign(document.createElement("div"), { className: "ex-chips" });
for (const value of values) {
const chip = Object.assign(document.createElement("button"), { textContent: String(value).replace(/^\d\. /, "") });
chip.dataset.slicer = slicer.id;
chip.dataset.value = value;
chip.onclick = () => toggle(slicer.id, String(value));
chips.append(chip);
}
host.append(title, chips);
}
paint();
});
// Setting a slicer is exactly the reader using it: every layer and chart bound to it follows.
// A list slicer's state is { values: [...] }; null clears it.
function toggle(slicerId, value) {
const set = chosen[slicerId];
set.has(value) ? set.delete(value) : set.add(value);
return map.setSlicerState({ slicerId, state: set.size ? { values: [...set] } : null });
}
document.getElementById("clear").onclick = () => map.clearAllSlicers();
document.getElementById("fit").onclick = () => map.fitLayer({ layerId: "cities", padding: 30, maxZoom: 6 });
// One handler covers your own changes (reason "command") and the reader's ("user").
map.on("slicerChanged", ({ slicerId, state }) => {
chosen[slicerId] = new Set(state?.values ?? []);
setTimeout(paint, 300); // give the map a moment to re-filter before counting
});
async function paint() {
for (const chip of document.querySelectorAll("[data-slicer]")) {
chip.classList.toggle("on", chosen[chip.dataset.slicer]?.has(chip.dataset.value) === true);
}
const stats = await map.getLayerStats({ layerId: "cities" });
document.getElementById("result").textContent = `${stats.visibleFeatureCount.toLocaleString()} cities match`;
}
</script>
</body>
</html>